哈囉,我們又見面了,前幾天我們把 Line 的 ChatBot 番外篇 完成了,今天我們來試著串接「第三方金流」的服務,在開始之前必須先釐清一件事:「第三方金流 和 行動支付、電子支付差在哪裡?」
詳細可以參考 行動支付?第三方支付?電子支付?別搞混了它們三個都不一樣!| 電獺少女,第三方金流主要功能就是,先向顧客代收交易金額,等交易完全成功,例如是顧客收到貨品確認沒問題,才撥款給電商平台,而第三方金流也不是免費的,錢經過了它的手,怎麼有不收過路費的道理呢 XD,所以就有 手續費 的存在拉,關於手續費和服務內容,也就是各家第三方金流所競爭的關鍵。
第三方金流就是你在電商網頁(博客來、蝦皮等等)上,進行結帳時會跳轉到一個要你輸入信用卡卡號的頁面,像下圖,要求你 填入卡號 或 選擇其他付款方式 的頁面,這就是第三方金流的服務。
今天我們要來嘗試的第三方金流廠商是 綠界,可以說是台灣最早的第三方金流廠商,除了綠界還有其他廠商,不過各家廠商的糾葛,就像連續劇一樣的情節了,我也不是很瞭解它們的關係 XD
有提供 Python SDK,支援以下支付方式
除了支援 All in One 金流之外,還有提供 物流整合服務,包含超商(全家、7-11、萊爾富)取貨付款,還有黑貓、宅配通,還有提供 電子發票的服務,算是相當完整,但手續費也不低 XD,文章下面有 2020 年 3 月的手續費表格截圖供參考。
驗證完 → 填寫基本資料,到目前的步驟沒什麼問題,就是基本的註冊會員,下一步的收款設定比較麻煩
這步驟需要決定,你是什麼商店、你賣哪些商品、提供身分或公司證明
因為我是個人戶,所以我放身分證正反面
到目前為止,已經可以接收非信用卡的收款了,如果要開通 接受信用卡收款 的功能、提領 的功能,需要另外由系統驗證證件,需要 2~3 個工作天的驗證流程,但實際上我提出之後在半小時左右就都驗證過了。
如果只是簡單的需要收款,可以直接透過「建立收款連結」,就可以產生一組 網址 或 QR code,像是 https://p.ecpay.com.tw/3E441 這樣的一串網址,而你只要把這組網址 或 QR code,轉貼到顧客看的到的地方(可能是你的文章或者是個人網頁等等),顧客就可以點進去網址,使用刷卡或超商付款等等的方式,透過各種方式給你錢 !
進到綠界的管理後台,點建立收款連結,然後填資料,建立一個固定金額的商品,如果有很多項商品,就需要建立多筆連結,如果你有串 金流 SDK 就不用手動新增了,可以透過後端程式邏輯,把你原本就有的訂單系統結合 SDK,新增 商品 與 收款連結 的對應關係。
因為各種付款方式有金額範圍限制,為了符合所有付款方式的最低限度,所以我才設 31 元這個奇怪的數字 XD
建立之後會得到一個連結、QR code,你只要把這串 網址 或 QR code 轉貼到 文章 或 私訊給你的顧客,他們就可以透過第三方金流來付款給你。
現在要模擬顧客刷卡的過程,自己結帳給自己 XD,點進去透過綠界產生的收款連結,就會跳轉到綠界的結帳頁面。
點下一步→ 填付款人的基本資料
填完基本資料後,選擇付款方式,因為這筆訂單是 31元,符合各類付款方式的範圍,就可以選各種付款方式。
填完信用卡資訊後,就近到熟悉的手機驗證頁面,可以看到特約商店是 GreenWorld 綠界
,相當於是我的信用卡付款給 綠界
,由 綠界
代管,等整筆訂單交易成功,綠界
再把訂單的 31 元扣除手續費,再放到 綠界帳戶
,需要的時候再申請 提領,將放在 綠界帳戶
的錢,匯款到個人/公司銀行帳戶。
最後結帳成功
在綠界的後台可以查詢每一筆訂單,包括 消費者姓名
、手機
、email
、付款方式
、付款狀態
等等,也可以決定是否 退款
被扣了 5 元,在國內使用 信用卡一次付清
的手續費是 2.75%,因為 31 元的 2.75% 低於最低手續費 5 元,所以就被收了 5 元,對於小額收款的電商平台來說,這是一個很大的抽成。
以我這一筆 31 元的訂單來講,就相當於是 16% 的手續費,非常高。
這張費率表是
2020-03-09
的截圖,不一定符合你現在觀看這篇文章時的手續費率。
因為是使用信用卡付款,還沒請款時,退款相對簡單,如果是已經請款了 或 客戶用的是別種結帳方式,那就要我們自己處理退款,也就是錢已經到綠界了,綠界是不會幫忙處理退款的,你需要用另外的帳戶來退款給顧客。
到這邊,已經瞭解綠界的操作流程了,再來就是後端Server 串接 第三方金流SDK 的部分。
Python
串接 綠界 All in One 金流 SDK
綠界提供 PHP、Java、Ruby、Node.js、C#(.Net) 和 Python,六種的程式語言的 SDK,而我們這篇使用的 Python 的 All in One SDK,在官方提供的 Github 上,除了有 SDK 之外,還有數個 sample codes,我們這邊參考的是 sample_create_order_ALL.py 這個 sample code。
首先需要先把 All in One SDK
放到 Django
專案底下
原本 sample code 長這樣,落落長,而我們真的需要修改的地方,用註解的方法標註,真正的修改方法需要參考官方文件,我寫文章時所參考的文件版本是 5.1.47 (2020-02-10)
。
把 sample_create_order_ALL.py 複製下來,並重新命名為 ecpay_testing.py
,放在 shop/
底下 (和 views.py
同層級),且把整個用一個叫做 main
的 function 包起來。
import importlib.util
# 第一個需要修改的,就是 SDK 路徑
spec = importlib.util.spec_from_file_location(
"ecpay_payment_sdk", # SDK檔名不用改
"/path/to/ecpay_payment_sdk.py" # 改成 django app name/sdk name,
# 以我把 SDK 放到 shop 為例,
# 我就是改成 "shop/ecpay_payment_sdk.py"
)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
from datetime import datetime
def main():
# 第二個需要修改的,商品資訊
order_params = {
'MerchantTradeNo': datetime.now().strftime("NO%Y%m%d%H%M%S"),
'StoreID': '',
'MerchantTradeDate': datetime.now().strftime("%Y/%m/%d %H:%M:%S"),
'PaymentType': 'aio',
'TotalAmount': 2000, # 商品金額
'TradeDesc': '訂單測試', # 商品描述
'ItemName': '商品1#商品2', # 商品名稱,用井字號當分行
'ReturnURL': 'https://www.ecpay.com.tw/return_url.php', # 顧客填完付款資料後的跳轉頁面
'ChoosePayment': 'ALL', # 顧客的付費方式
# 結帳後,先導到 OrderResultURL,從綠界頁面跳回的頁面
# 如果沒有參數才會跳轉到 ClientBackURL
'ClientBackURL': 'https://www.ecpay.com.tw/client_back_url.php',
'ItemURL': 'https://www.ecpay.com.tw/item_url.php', # 商品資訊頁面
'Remark': '交易備註', # 備註文字
'ChooseSubPayment': '',
# 結帳成功/失敗後的結果頁面,告知顧客本次的結帳結果
'OrderResultURL': 'https://www.ecpay.com.tw/order_result_url.php',
'NeedExtraPaidInfo': 'Y',
'DeviceSource': '',
'IgnorePayment': '',
'PlatformID': '',
'InvoiceMark': 'N',
'CustomField1': '',
'CustomField2': '',
'CustomField3': '',
'CustomField4': '',
'EncryptType': 1,
}
extend_params_1 = {
'ExpireDate': 7, # 商品上架期限
'PaymentInfoURL': 'https://www.ecpay.com.tw/payment_info_url.php', #付款資訊頁面
'ClientRedirectURL': '', # 看完付款資訊,要重導到哪裡
}
extend_params_2 = {
'StoreExpireDate': 15,
'Desc_1': '',
'Desc_2': '',
'Desc_3': '',
'Desc_4': '',
'PaymentInfoURL': 'https://www.ecpay.com.tw/payment_info_url.php',
'ClientRedirectURL': '',
}
extend_params_3 = {
'BindingCard': 0,
'MerchantMemberID': '',
}
extend_params_4 = {
'Redeem': 'N',
'UnionPay': 0,
}
# 發票資訊
inv_params = {
# 'RelateNumber': 'Tea0001', # 特店自訂編號
# 'CustomerID': 'TEA_0000001', # 客戶編號
# 'CustomerIdentifier': '53348111', # 統一編號
# 'CustomerName': '客戶名稱',
# 'CustomerAddr': '客戶地址',
# 'CustomerPhone': '0912345678', # 客戶手機號碼
# 'CustomerEmail': 'abc@ecpay.com.tw',
# 'ClearanceMark': '2', # 通關方式
# 'TaxType': '1', # 課稅類別
# 'CarruerType': '', # 載具類別
# 'CarruerNum': '', # 載具編號
# 'Donation': '1', # 捐贈註記
# 'LoveCode': '168001', # 捐贈碼
# 'Print': '1',
# 'InvoiceItemName': '測試商品1|測試商品2',
# 'InvoiceItemCount': '2|3',
# 'InvoiceItemWord': '個|包',
# 'InvoiceItemPrice': '35|10',
# 'InvoiceItemTaxType': '1|1',
# 'InvoiceRemark': '測試商品1的說明|測試商品2的說明',
# 'DelayDay': '0', # 延遲天數
# 'InvType': '07', # 字軌類別
}
# 建立實體
ecpay_payment_sdk = module.ECPayPaymentSdk(
# 參考綠界後台->系統開發管理->系統界接設定,開發時有測試用的 商店ID
MerchantID='2000132',
# 參考綠界後台->系統開發管理->系統界接設定,開發時有測試用的 HashKey
HashKey='5294y06JbISpM5x9',
# 參考綠界後台->系統開發管理->系統界接設定,開發時有測試用的 HashIV
HashIV='v77hoKGq4kWxNNIS'
)
# 合併延伸參數
order_params.update(extend_params_1)
order_params.update(extend_params_2)
order_params.update(extend_params_3)
order_params.update(extend_params_4)
# 合併發票參數
order_params.update(inv_params)
try:
# 產生綠界訂單所需參數
final_order_params = ecpay_payment_sdk.create_order(order_params)
# 產生 html 的 form 格式
action_url = 'https://payment-stage.ecpay.com.tw/Cashier/AioCheckOut/V5' # 測試環境
# action_url = 'https://payment.ecpay.com.tw/Cashier/AioCheckOut/V5' # 正式環境
html = ecpay_payment_sdk.gen_html_post_form(action_url, final_order_params)
# 最後產出 html,回傳回去顯示此 html
return html
except Exception as error:
print('An exception happened: ' + str(error))
views.py
導入 ecpay_testing.py
的 main()
from .ecpay_testing import main
@csrf_exempt
def ecpay_view(request):
return HttpResponse(main())
urls.py
把這個測試頁面,綁在 ecpay/
的網域底下,所以 urls.py
長這樣
urlpatterns = [
...
path('ecpay/', ecpay_view),
]
$ python manage.py runserver
127.0.0.1:8000/ecpay/
進入到測試頁面
在結帳前,還會告知目前是測試環境
到目前為止,算是初次使用 綠界所提供的 All in One SDK,還沒有真正串接起來,因為中間還漏了 CheckMacValue 的驗證流程,在文件的第 43 頁有解釋驗證流程該怎麼進行,但我暫時還沒有要完整的接起來,就不浪費時間在確認驗證流程了,可以參考【Flask 教學】Python 綠界金流 API 信用卡串接 | Max行銷誌,雖然我用了它的方法還是驗證失敗 QQ
串接 SDK 最麻煩的就是 驗證,尤其還有 加解密、編碼 的問題,非常麻煩,需要一步一步核對文件所描述的步驟,去確認每一步的輸出都是正確的,非常耗時間跟腦力,尤其是邊做的時候,邊腦中出現一句話「接起來是應該的,接不起來是你太弱」,就會覺得心累 XD
我就帶大家走到這步,後續驗證的苦差事就交給各位自己解決了,尤其是 程式語言 和 作業系統 的 預設編碼不一致,非常容易出錯,就算我今天做出來了,放到不同的作業系統說不定又不行,所以必須把 收到的資料 和 送出的資料 的編碼寫清楚,確保每次進來和出去的編碼符合文件需求。
這系列終於要結束了,很期待下一個系列的到來,又可以替自己刷新一套世界觀了~
我是 RS,這是我的 不做怎麼知道系列 文章,我們 明天見。
不好意思,想問一下,當確認付款完後,到入以下頁面後
https://www.ecpay.com.tw/order_result_url.php#
出現以下錯誤訊息
Sorry! 很抱歉,目前網頁無回應,請重新整理或稍後再試!已通知相關人員協助處理。
想請問不知道樓主有沒有經驗,這個錯誤的原因呢
嗨,
把建立訂單的 OrderResultURL
參數拿掉就好了
從綠界的文件來看,在建立綠界訂單的時候,有幾個比較像的參數要注意:
OrderResultURL
: (選填)
ClientBackURL
只能擇一填,差別在於 ClientBackURL
不會帶付款結果,而 OrderResultURL
會帶付款結果ClientBackURL
: (選填)
ReturnURL
: (必填)
POST
API 給綠界,當使用者付款完畢,或取消付款,綠界都會發付款結果給我們的 Server這幾個真的很容易搞混,我自己每次要接的時候,都還要回來看文件QQ
所以以你的情況來說,只要把 OrderResultURL
拿掉,付款後就不會跳出你剛講的頁面
成功解決了!非常感謝您,原來是我還沒有完全理解他的code!!謝謝您的文章~
不客氣~
順便推廣一下我自己哈哈哈,我還有自己的 YT 頻道,有興趣可以訂閱~